home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
amisl090.zip
/
NOTE.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-09-12
|
26KB
|
1,010 lines
;-----------------------------------------------------------------------
; NOTE.ASM Public Domain 1992 Ralf Brown
; You may do with this software whatever you want, but
; common courtesy dictates that you not remove my name
; from it.
;
; Popup to append one or more lines to a text file. Demonstration of the
; use of DOS from within an AMIS-compliant TSR.
; Note: popup may be done from the commandline or via a hotkey; however,
; the hotkey support requires a newer BIOS which has the INT 15/4F
; keyboard intercept
;
; Version 0.90
; LastEdit: 9/10/92
;-----------------------------------------------------------------------
__TINY__ equ 1 ; using Tiny model
INCLUDE AMIS.MAC
@Startup 3,00 ; need DOS 3.00
; this macro also takes care of declaring
; all the segments in the required order
;-----------------------------------------------------------------------
;
VERSION_NUM equ 005Ah ; v0.90
VERSION_STR equ "0.90"
; uncomment the following line to use the generic hotkey dispatcher, at a cost
; of an additional 80 bytes
;CUSTOM_HOTKEY_CODE equ 1
WINDOW_TOP equ 0 ; topmost row of TSR's popup window
WINDOW_LEFT equ 5 ; leftmost column of TSR's popup window
WINDOW_HEIGHT equ 3 ; height (including frame) of popup window
WINDOW_WIDTH equ 70 ; width (including frame) of popup window
LOCAL_STACK_SIZE equ 128 ; size of local stack in bytes
HOTKEY_SCAN equ SCAN_N ; scan code for 'N' key
HOTKEY_NAME equ "N"
LODSB_ES MACRO
DB 26h,0ACh ; LODSB ES:
ENDM
;-----------------------------------------------------------------------
; Put the resident code into its own segment so that all the offsets are
; proper for the new location after copying it into a UMB or down into
; the PSP.
;
TSRcode@
;-----------------------------------------------------------------------
; Since we need a PSP, but might be loaded into a UMB or at the top of
; conventional memory, we make a copy of the all-important first 64 bytes
; of the PSP here. After relocation, this copy will start at offset 0
;
TSR_PSP db 64 dup (?)
;-----------------------------------------------------------------------
; TSR's initialized data storage
;
TSRdata@
TSR_name db "NOTE",0 ; title for popup window
int13_25_busy label word ; allow both to be tested in one operation
int13_busy db 0
int25_busy db 0
int26_TSR_busy label word ; allow both to be tested in one operation
int26_busy db 0
TSR_activated db 0
want_popup db 0
want_shutdown db 0
popup_INT28 db 0
;;; add TSR-specific initialized data below
CRLF_buffer db 13,10
TSRdataEnd@
;-----------------------------------------------------------------------
; TSR's uninitialized data storage
;
TSRbss@
INDOS_ptr dd ?
CRITERR_ptr dd ?
interrupted_DTA dd ?
interrupted_PSP dw ?
interrupted_SP dw ?
interrupted_SS dw ?
interrupted_cursorpos dw ?
display_page_attr label word
display_attr db ?
display_page db ?
screen_width db ?
cursor_pos label word
cursor_x db ?
cursor_y db ?
screen_buffer db (WINDOW_HEIGHT*WINDOW_WIDTH*2) dup (?)
local_stack db LOCAL_STACK_SIZE dup (?)
local_stack_bottom label byte
;;; add TSR-specific uninitialized data below
notefile_handle dw ?
edit_buffer db WINDOW_WIDTH-2 dup (?)
TSRbssEnd@
;-----------------------------------------------------------------------
TSR_main proc near
ASSUME DS:TGROUP,ES:NOTHING
xor si,si ; SI stores line length
TSR_main_loop:
mov dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
add dx,si
call TSR_move_cursor
call TSR_getkey
cmp al,0Dh ; Enter pressed?
je TSR_main_line_end
cmp al,27 ; Esc pressed?
je TSR_main_done
cmp al,8
je backspace
cmp al,0 ; extended ASCII?
je TSR_main_loop ; if yes, ignore
cmp al,0E0h
jne got_char
cmp ah,0
jne TSR_main_loop
got_char:
cmp si,WINDOW_WIDTH-2
jb store_char
beep:
mov ax,0E07h ; beep
int 10h
jmp TSR_main_loop
store_char:
mov edit_buffer[si],al
inc si ; remember that we got another char
call TSR_put_char
jmp TSR_main_loop
backspace:
or si,si
jz beep
dec si
mov dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
add dx,si
call TSR_move_cursor
mov al,' '
call TSR_put_char
jmp TSR_main_loop
TSR_main_line_end:
mov ah,40h
mov bx,notefile_handle
mov cx,si
mov dx,offset TGROUP:edit_buffer
int 21h
mov ah,40h
mov cx,2
mov dx,offset TGROUP:CRLF_buffer
int 21h
call TSR_clear_window
jmp TSR_main ; restart for next line
TSR_main_done:
mov bx,notefile_handle
mov ah,45h ; DUP handle
int 21h
jc TSR_main_exit ; quit now if unable to duplicate
mov bx,ax
mov ah,3Eh ; close duplicate
int 21h
TSR_main_exit:
ret
TSR_main endp
;-----------------------------------------------------------------------
; Function that performs any necessary cleanup prior to the TSR being
; removed from memory. At the time it is called, the TSR is effectively
; popped up, though it has not modified the screen. If this routine needs
; to write on the screen, it must save and restore the screen contents
; itself
;
TSR_shutdown proc near
mov bx,notefile_handle
mov ah,3Eh ; close the file
int 21h
ret
TSR_shutdown endp
;-----------------------------------------------------------------------
TSR_INT24_handler:
mov al,03h ; FAIL, for now
; iret ; save a byte by falling through to next handler
;-----------------------------------------------------------------------
; Simply ignore Ctrl-Break and Ctrl-C interrupts
;
TSR_INT1B_handler:
TSR_INT23_handler:
iret
;=======================================================================
; It should not be necessary to make any changes between here and the
; end of the resident portion (other than the TSR identifier in the ALTMPX
; macro) in order to modify this code for a different purpose.
;=======================================================================
;-----------------------------------------------------------------------
;
TSR_getkey proc near
mov ah,11h ; keystroke available?
int 16h
jnz TSR_getkey_got_one ; if yes, get it, otherwise
int 28h ; give other TSRs a chance to do work
jmp TSR_getkey
TSR_getkey_got_one:
mov ah,10h ; get the keystroke
int 16h
ret
TSR_getkey endp
;-----------------------------------------------------------------------
; entry: DH = row, DL = column
;
TSR_move_cursor proc near
ASSUME DS:TGROUP,ES:NOTHING
mov cursor_pos,dx
mov bh,display_page
mov ah,2 ; BIOS move-cursor function
int 10h
ret
TSR_move_cursor endp
;-----------------------------------------------------------------------
; exit: AX,BX,CX,DX destroyed
;
TSR_put_char_186 proc near
mov al,186
;; fall through to TSR_put_char
TSR_put_char_186 endp
;-----------------------------------------------------------------------
; entry: AL = char
; exit: AH,BX,CX,DX destroyed
;
TSR_put_char proc near
mov cx,1
;; fall through to TSR_put_line
TSR_put_char endp
;-----------------------------------------------------------------------
; entry: AL = char, CX = repeat count
; exit: AX,BX,CX,DX destroyed
;
TSR_put_line proc near
ASSUME DS:TGROUP,ES:NOTHING
add cursor_x,cl
mov bx,display_page_attr
mov ah,9
int 10h
mov al,cursor_x
cmp al,screen_width
jb TSR_put_line_done
mov cursor_x,0
inc cursor_y
;
; need to handle case of falling off the bottom
;
TSR_put_line_done:
mov dx,cursor_pos
mov ah,2 ; set cursor position
int 10h
ret
TSR_put_line endp
;-----------------------------------------------------------------------
save_screen proc near
ASSUME DS:TGROUP,ES:NOTHING
mov ah,0Fh
int 10h ; get video mode and active page
mov display_page,bh
mov screen_width,ah
mov ah,3 ; get cursor position on page BH
int 10h
mov interrupted_cursorpos,dx
push ds
pop es
ASSUME ES:TGROUP
mov di,offset TGROUP:screen_buffer
mov dh,WINDOW_TOP
save_screen_loop1:
mov dl,WINDOW_LEFT
save_screen_loop2:
mov ah,2 ; set cursor position on page BH
int 10h
mov ah,8 ; read character&attribute on page BH
int 10h
stosw ; and remember them for later restore
inc dl
cmp dl,WINDOW_LEFT+WINDOW_WIDTH
jb save_screen_loop2
inc dh
cmp dh,WINDOW_TOP+WINDOW_HEIGHT
jb save_screen_loop1
ret
save_screen endp
;-----------------------------------------------------------------------
framed_window_hline proc near
push ax
call TSR_put_char
mov cx,WINDOW_WIDTH-2
mov al,205
call TSR_put_line
pop ax
mov al,ah
jmp TSR_put_char
framed_window_hline endp
;-----------------------------------------------------------------------
framed_window proc near
ASSUME DS:TGROUP,ES:NOTHING
mov dx,256*WINDOW_TOP + WINDOW_LEFT
call TSR_move_cursor
mov display_attr,0Fh ; bright white on black
mov ax,0BBC9h ; double upper left/right corners
call framed_window_hline
push si
mov dx,256*(WINDOW_TOP+1) + WINDOW_LEFT
frame_loop:
mov si,dx
call TSR_move_cursor
call TSR_put_char_186 ; double vertical bar
mov dx,si
mov dl,WINDOW_LEFT+WINDOW_WIDTH-1
call TSR_move_cursor
call TSR_put_char_186 ; double vertical bar
mov dx,si
inc dh
cmp dh,WINDOW_TOP+WINDOW_HEIGHT-1
jb frame_loop
pop si
mov dx,256*(WINDOW_TOP+WINDOW_HEIGHT-1) + WINDOW_LEFT
call TSR_move_cursor
mov display_attr,0Fh ; bright white on black
mov ax,0BCC8h ; double lower left/right corners
call framed_window_hline
;
; frame is done, now add the title
;
mov dx,256*WINDOW_TOP + (WINDOW_LEFT+2)
call TSR_move_cursor
mov si,offset TGROUP:TSR_name
frame_name_loop:
lodsb
or al,al
jz frame_name_done
call TSR_put_char
jmp frame_name_loop
frame_name_done:
mov dx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
call TSR_move_cursor
mov display_attr,07h ; dim white on black
;; fall through to TSR_clear_window ;;
framed_window endp
;-----------------------------------------------------------------------
TSR_clear_window proc near
mov bh,display_attr
mov cx,256*(WINDOW_TOP+1) + (WINDOW_LEFT+1)
mov dx,256*(WINDOW_TOP+WINDOW_HEIGHT-2) + (WINDOW_LEFT+WINDOW_WIDTH-2)
mov ax,0600h ; clear popup window area
int 10h
ret
TSR_clear_window endp
;-----------------------------------------------------------------------
restore_screen proc near
ASSUME DS:TGROUP,ES:NOTHING
mov si,offset TGROUP:screen_buffer
mov dh,WINDOW_TOP
rest_screen_loop1:
mov dl,WINDOW_LEFT
rest_screen_loop2:
mov ah,2
mov bh,display_page
int 10h ; set cursor position
lodsw ; get character and attribute to restore
mov bl,ah ; BL <- attribute
mov cx,1
mov ah,9 ; write character&attribute
int 10h
inc dl
cmp dl,WINDOW_LEFT+WINDOW_WIDTH
jb rest_screen_loop2
inc dh
cmp dh,WINDOW_TOP+WINDOW_HEIGHT
jb rest_screen_loop1
mov dx,interrupted_cursorpos
mov ah,2 ; restore cursor position
int 10h
ret
restore_screen endp
;-----------------------------------------------------------------------
; requires DS = TGROUP and interrupts enabled on entry; may destroy BX
;
popup proc near
mov TSR_activated,1 ; yes, we are now active
mov want_popup,0 ; and we are finally popping up
;
; switch to a local stack so that we are assured of enough stack space
;
push ax
mov interrupted_SS,ss
mov interrupted_SP,sp
mov ax,cs
cli
mov ss,ax ; switch stack
ASSUME SS:TGROUP
mov sp,offset RESIDENT_CODE:local_stack_bottom
sti
push es
push di
push si
push bp
push dx
push cx
push bx
;
; switch to our own PSP and store current DTA
;
mov ah,51h
int 21h ; get PSP of interrupted program
mov interrupted_PSP,bx
mov bx,cs
mov ah,50h ; set PSP to our own
int 21h
mov ah,2Fh ; get DTA
int 21h
ASSUME ES:NOTHING
mov word ptr interrupted_DTA,bx
mov word ptr interrupted_DTA+2,es
GRAB_INTERRUPT 1Bh,TSR_INT1B_handler
GRAB_INTERRUPT 23h,TSR_INT23_handler
GRAB_INTERRUPT 24h,TSR_INT24_handler
mov al,0
xchg al,want_shutdown ; get and clear shutdown flag
or al,al ; was it set?
jz do_popup ; if not, regular popup
call TSR_shutdown
jmp short popup_done
do_popup:
call save_screen
call framed_window
call TSR_main ; the actual guts of the TSR
call restore_screen
popup_done:
RESTORE_INTERRUPT 1Bh
RESTORE_INTERRUPT 23h
RESTORE_INTERRUPT 24h
;
; restore the original PSP and DTA
;
mov bx,interrupted_PSP
mov ah,50h ; set PSP back to stored value
int 21h
push ds
lds dx,interrupted_DTA
ASSUME DS:NOTHING
mov ah,1Ah ; set DTA back to stored value
int 21h
pop ds ; restore DS
ASSUME DS:TGROUP
pop bx
pop cx
pop dx
pop bp
pop si
pop di
pop es
;
; finally, switch back to original stack
;
cli
mov ss,interrupted_SS
ASSUME SS:NOTHING
mov sp,interrupted_SP
sti
pop ax
mov TSR_activated,0 ; no longer popped up, so OK to pop again
ret
popup endp
;-----------------------------------------------------------------------
attempt_popup proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
mov want_popup,1 ; remember that a popup was requested
;; fall through to try_popup ;;
attempt_popup endp
try_popup proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
pushf
sti ; OK to interrupt
cmp want_popup,0
je try_popup_done
push ax
mov ax,int13_25_busy ; check disk activity flags
or ax,int26_TSR_busy ; and whether already popped up
pop ax
jnz try_popup_done ; can't popup if any of those flags set
push ds
push bx
lds bx,INDOS_ptr ; check InDOS flag
ASSUME DS:NOTHING
cmp byte ptr [bx],1
jb try_popup_1 ; if zero, DOS is probably idle
ja try_popup_2 ; if not 0 or 1, DOS is definitely busy
cmp popup_INT28,0 ; if activated via INT 28, INDOS flag is
jz try_popup_2 ; allowed to be 1 rather than 0
try_popup_1:
lds bx,CRITERR_ptr ; InDOS says DOS is idle, but it might
ASSUME DS:NOTHING ; be in the critical error handler
cmp byte ptr [bx],0 ; so check the CritErr flag
jne try_popup_2 ; can't popup if in critical error
push cs
pop ds ; restore DS
ASSUME DS:TGROUP
call popup ; whew, we made it... we can pop up now
try_popup_2:
ASSUME DS:NOTHING
pop bx ; restore registers
pop ds
ASSUME DS:NOTHING
try_popup_done:
popf
ret
try_popup endp
;-----------------------------------------------------------------------
API_popup proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
call attempt_popup
mov al,AMIS_POPUP_WILLDO ; can't pop up now, will do so when able
cmp want_popup,1 ; did we manage to pop up?
je API_popup_done
mov al,AMIS_SUCCESSFUL ; successful
xor bx,bx ; no return code
API_popup_done:
ret
API_popup endp
;-----------------------------------------------------------------------
remov proc near
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
inc want_shutdown
inc want_popup
call try_popup
mov al,0
xchg al,want_shutdown ; get and clear shutdown flag
cmp al,0 ; if no longer set, shutdown successful
je remov_successful
dec want_popup ; clear popup request
mov al,AMIS_UNINST_TRYLATER ; can't remove at this time
ret
remov_successful:
mov al,AMIS_UNINST_SAFE_OFF ; no resident remover, now disabled
mov bx,0 ; seg of block to free (will be patched)
ALTMPX$PSP equ word ptr ($-2) ; magic name of word to be patched with
; actual memory block segment by TSR
; installation code
ret
remov endp
;-----------------------------------------------------------------------
; Declare the interrupt vectors hooked by the program, then set up the
; Alternate Multiplex Interrupt Spec handler
;
HOOKED_INTS 08h,13h,15h,25h,26h,28h
HOTKEYS HK_INT15ENTRY
HOTKEY HOTKEY_SCAN,HK_BOTHSHIFT,<HK_ANYCTRL OR HK_ANYALT>
HOTKEYS_DONE
ALTMPX 'Ralf B','NOTE',VERSION_NUM,"Append notes to a file",,,API_popup,remov,Y,hotkey_list
;-----------------------------------------------------------------------
; If we can't pop up immediately because DOS or disk I/O is busy, try to pop
; up on a subsequent timer tick
; We can save one byte by specifying the hardware reset handler set up by
; the ALTMPX macro above
;
int08_handler proc far
ISP_HEADER 08h,hw_reset_2Dh
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
pushf
call ORIG_INT08h ; chain to previous handler
call try_popup ; if need to pop up, try to do so now
iret
int08_handler endp
;-----------------------------------------------------------------------
; Can't pop up when disk is busy, so try to pop up on return
;
int13_handler proc far
ISP_HEADER 13h
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
sti ; OK to interrupt here
inc int13_busy
push bp ; now, restore original state of flags,
mov bp,sp ; especially IF
push word ptr [bp+6] ; original flags before INT 13h
popf ; restore original flags
pop bp
pushf ; simulate INT 13h
call ORIG_INT13h
pushf ; preserve returned flags
dec int13_busy
popf ; restore returned flags
call try_popup ; pop up if requested (saves all regs)
ret 2
int13_handler endp
;-----------------------------------------------------------------------
; Can't pop up when doing a raw read from disk, so try to pop up on return.
; We can save one byte by specifying the hardware reset handler set up by
; the INT 13h handler above
;
int25_handler proc far
ISP_HEADER 25h,hw_reset_13h
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
sti ; OK to interrupt here
inc int25_busy
push bp ; now, restore original state of flags,
mov bp,sp ; especially IF
push word ptr [bp+6] ; original flags before INT 25h
popf ; restore original flags
pop bp
pushf ; simulate INT 25h
call ORIG_INT25h
pushf ; preserve returned flags
dec int25_busy
int25_26_try_popup:
popf ; restore returned flags
call try_popup ; pop up if requested (saves all regs)
ret
int25_handler endp
;-----------------------------------------------------------------------
; Can't pop up when doing a raw write to disk, so try to pop up on return.
; We can save one byte by specifying the hardware reset handler set up by
; the INT 13h handler above
;
int26_handler proc far
ISP_HEADER 26h,hw_reset_13h
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
sti ; OK to interrupt here
inc int26_busy
push bp ; now, restore original state of flags,
mov bp,sp ; especially IF
push word ptr [bp+6] ; original flags before INT 26h
popf ; restore original flags
pop bp
pushf ; simulate INT 26h
call ORIG_INT26h
pushf ; preserve returned flags
dec int26_busy
jmp int25_26_try_popup
int26_handler endp
;-----------------------------------------------------------------------
; Can't pop up when DOS is busy, but can do so during an INT 28h
;
ISP_HEADER 28h
pushf
inc popup_INT28
call try_popup
dec popup_INT28
popf ; restore flags before chaining
jmp ORIG_INT28h
;-----------------------------------------------------------------------
; Hotkey checker. Hotkey is Shift+Shift+Key, where Key is patched in at
; installation.
; We can save one byte by specifying the hardware reset handler set up by
; the INT 28h handler above
;
IFDEF CUSTOM_HOTKEY_CODE
int15_handler proc far
ISP_HEADER 15h,hw_reset_28h
ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING
pushf
sti ; OK to be interrupted
cmp ax,4F00h+HOTKEY_SCAN ; can also patch with actual scan code
hotkey_scancode equ byte ptr ($-2) ; at installation time
jne not_hotkey
cmp TSR_activated,0
jne not_hotkey ; ignore hotkey if already popped up
push ds
push ax
xor ax,ax
mov ds,ax
mov al,ds:[417h] ; get shift states
and al,0Fh ; mask out all but Shift/Ctrl/Alt
cmp al,3 ; both Shift keys pressed?
pop ax
pop ds
jne not_hotkey
;
; yes, we got our hotkey
;
popf
call attempt_popup ; request a popup (preserves flags)
clc ; throw out scan code
ret 2 ; and return so nobody else acts on it
not_hotkey:
popf ; restore flags
jmp ORIG_INT15h
int15_handler endp
ELSE
hotkey_funcs label word ; list of hotkey handlers
dw attempt_popup
HOTKEY_DISPATCHER AFTER,hotkey_funcs
ENDIF
TSRcodeEnd@
;-----------------------------------------------------------------------
_TEXT SEGMENT 'CODE'
ASSUME cs:_TEXT,ds:NOTHING,es:NOTHING,ss:NOTHING
banner db 'NOTE v',VERSION_STR,' Public Domain 1992 Ralf Brown',13,10,'$'
usage_msg db "Usage:",9,"NOTE -Ifile",9,"Install using <file> as notepad",13,10
db 9,"NOTE -R",9,9,"Remove from memory",13,10
db "$"
hotkey_msg db "Press Shift-Shift-",HOTKEY_NAME," to pop up",13,10,"$"
no_hotkey_msg db "Hotkey is not available on this machine",13,10,"$"
hotkey_used_msg db "Hotkey is already in use.",13,10,"$"
installed_msg db "Installed.",13,10,"$"
already_inst_msg db 13,10,"Already installed.",13,10,"$"
cant_remove_msg db "Can't remove from memory.",13,10,"$"
uninstalled_msg db "Removed.",13,10,"$"
cant_access_msg db "Unable to open or create notepad file",13,10,"$"
filename_len equ 80
filename_buf db filename_len dup (?)
@Startup2 Y
push ds
pop es
ASSUME ES:_INIT
push cs
pop ds
ASSUME DS:_TEXT
;
; say hello
;
DISPLAY_STRING banner
mov bx,1000h ; set memory block to 64K
mov ah,4Ah
int 21h
mov si,81h ; SI -> command line
cld ; ensure proper direction for string ops
cmdline_loop:
lodsb_es
cmp al,' ' ; skip blanks and tabs on commandline
je cmdline_loop
cmp al,9
je cmdline_loop
cmp al,'-'
je got_cmdline_switch
bad_cmdline:
jmp usage
got_cmdline_switch:
lodsb_es ; get next character
and al,0DFh ; force to uppercase
cmp al,'R'
jne not_removing
jmp removing
not_removing:
cmp al,'I'
jne bad_cmdline
installing:
;
; place any necessary pre-initialization here
;
mov di,offset _TEXT:filename_buf
mov dx,di ; remember start of filename
mov cx,filename_len
push es
pop ds
ASSUME DS:_INIT
push cs
pop es
ASSUME ES:_TEXT
copy_filename_loop:
lodsb
cmp al,' '
jb copy_filename_done
stosb
loop copy_filename_loop
copy_filename_done:
mov al,0
stosb
push cs
pop ds
ASSUME DS:_TEXT
mov ax,3DC1h ; open, no-inherit/DENYNONE/write-only
int 21h
jnc open_successful
mov ax,3C00h ; if unable to open, try creating file
xor cx,cx ; no special attributes
int 21h
jnc create_successful
mov dx,offset _TEXT:cant_access_msg
jmp exit_with_error
open_successful:
create_successful:
push cs
pop ds ; restore DS
ASSUME DS:_TEXT
mov bx,ax
mov ah,3Eh ; close the file again; we now know
int 21h ; we can access it
;
; find out whether keyboard intercept is available
;
stc
mov ah,0C0h
int 15h ; get ROM BIOS configuration data
ASSUME ES:NOTHING
mov dx,offset _TEXT:no_hotkey_msg
jc no_kbd_intercept
test byte ptr es:[bx+5],10h ; have keyboard intercept?
jz no_kbd_intercept
mov dx,offset _TEXT:hotkey_msg
no_kbd_intercept:
mov ah,9
int 21h
;
; get and store pointers to DOS busy flags
;
mov ah,34h ; get address of InDOS flag
int 21h
ASSUME ES:NOTHING
mov ds,TGROUP@
ASSUME DS:TGROUP
mov word ptr TGROUP:INDOS_ptr,bx
mov word ptr TGROUP:INDOS_ptr+2,es
push ds
mov ax,5D06h ; get address of CriticalError flag
int 21h
ASSUME DS:NOTHING
mov dx,ds
pop ds
ASSUME DS:TGROUP
mov word ptr TGROUP:CRITERR_ptr+2,dx
mov word ptr TGROUP:CRITERR_ptr,si
;
; one last check: is there a hotkey conflict?
;
IF_HOTKEY_USED hotkey_in_use
;
; now go install the TSR
;
push cs
pop ds
ASSUME DS:_TEXT
;note: add TOPMEM following BEST to make TSR load at top of memory
INSTALL_TSR ,BEST,,inst_patch,already_installed
hotkey_in_use:
push cs
pop ds
ASSUME DS:_TEXT
mov dx,offset hotkey_used_msg
jmp short exit_with_error
removing:
ASSUME DS:_TEXT
UNINSTALL cant_uninstall
push cs
pop ds
ASSUME DS:_TEXT
DISPLAY_STRING uninstalled_msg
mov ax,4C00h
int 21h
already_installed:
mov dx,offset _TEXT:already_inst_msg
jmp short exit_with_error
usage:
ASSUME DS:_TEXT
mov dx,offset _TEXT:usage_msg
jmp short exit_with_error
cant_uninstall:
mov dx,offset _TEXT:cant_remove_msg
exit_with_error:
push cs
pop ds
ASSUME DS:_TEXT
mov ah,9
int 21h
mov ax,4C01h
int 21h
inst_patch:
ASSUME DS:NOTHING
push ds
push es
mov es,ax
ASSUME ES:TGROUP
;
; close all files which will not be used by the TSR
;
mov bx,0 ; for this TSR, don't need handles 0-4
close_file_loop:
mov ah,3Eh
int 21h
inc bx
cmp bx,4
jbe close_file_loop
;
; now copy the PSP into the resident portion
;
mov ds,__psp
ASSUME DS:_INIT
xor si,si
xor di,di
mov cx,size TSR_PSP
cld
rep movsb
mov es:[36h],es ; adjust JFT pointer in copied PSP
mov bx,es
mov ah,50h ; set PSP segment so TSR owns file
int 21h
push cs
pop ds
ASSUME DS:_TEXT
mov dx,offset _TEXT:filename_buf
mov ax,3DC1h ; open, no-inherit/DENYNONE/write-only
int 21h
jnc reopen_successful
xor ax,ax ; point at a closed handle
reopen_successful:
mov TGROUP:notefile_handle,ax
mov bx,ax
xor cx,cx
xor dx,dx
mov ax,4202h ; position to end of file
int 21h
mov ah,50h ; restore PSP segment
mov bx,__psp
mov ds,bx
ASSUME DS:_INIT
int 21h
;
; now, zero out the JFT in our PSP so that the exit won't close
; the files that the TSR does need
;
mov cx,ds:[0032h] ; size of JFT
les di,ds:[0034h] ; pointer to JFT
mov al,0FFh ; closed-file flag
rep stosb
pop es
ASSUME ES:NOTHING
;
; finally, announce that we are installed
;
push cs
pop ds
ASSUME DS:_TEXT
DISPLAY_STRING installed_msg
pop ds
ASSUME DS:NOTHING
ret
_TEXT ENDS
end INIT